<script setup lang="ts">
import nodeType, { NodeComponents } from "./ProcessNodes";
import type { FlowModelNode } from "./ProcessDef";
import { ElMessage } from "element-plus";
import { onMounted, reactive, ref } from "vue";
import * as runNodeApi from "@/api/flow/runnode";

const props = defineProps({
  readonly: {
    type: Boolean,
    //流程图只读模式
    default: false
  },
  flowInstId: {
    type: String,
    default: null
  }
});

const emit = defineEmits(["select"]);
const flowDef = defineModel<FlowModelNode[]>();
const nodeRef = ref<any[]>();

const state = reactive({
  mounted: false,
  flowHistory: []
});

onMounted(() => {
  // 查看流程图时传入流程实例id
  state.mounted = true;
  if (props.flowInstId) {
    runNodeApi.queryList({ flowInstId: props.flowInstId }).then(res => {
      // nextTick(() => {
      //   state.mounted = true;
      // });
      if (res.code === 200) {
        state.flowHistory = res.data;
      }
    });
  }
});

/**
 * 删除某个元素
 * @param branch 要删除的元素所在支路
 * @param i 删除的元素在该支路内索引位置
 */
function deleteNode(branch, i) {
  branch.splice(i, 1);
}

/**
 * 插入节点
 * @param branch 该节点要插入的支路（节点数组）
 * @param i 插入哪个元素后面的索引，实际插入位置为i+1
 * @param type 要插入的节点类型
 */
function insertNode(branch, i, type) {
  if (nodeType[type]) {
    const nodeTo = nodeType[type].create();
    branch.splice(i + 1, 0, nodeTo);
  } else {
    ElMessage.warning("请在ProcessNodes.js内配置该节点");
  }
}

function validate() {
  return new Promise((resolve, reject) => {
    const errs = [] as string[];
    if (Array.isArray(flowDef.value)) {
      const endNode = flowDef.value.filter(item => {
        return item.type === "End";
      });
      if (endNode.length < 1) {
        errs.push("流程未包含结束节点");
      }
    }
    if (nodeRef.value && Array.isArray(nodeRef.value)) {
      if (nodeRef.value?.length < 3) {
        errs.push("流程至少应该包含开始节点、一个任务节点和结束节点");
      } else {
        nodeRef.value.forEach(ref => {
          if (ref.validate) {
            ref.validate(errs);
          }
        });
      }
    }
    if (errs.length === 0) {
      resolve([]);
    } else {
      reject(errs);
    }
  });
}

const handleSelectNode = node => {
  emit("select", node);
};

defineExpose({ validate });
</script>

<template>
  <div>
    <div>
      <div v-if="state.mounted" class="w-process">
        <template v-for="(node, i) in flowDef" :key="node.code + node.type">
          <component
            ref="nodeRef"
            v-model="flowDef[i]"
            :readonly="readonly"
            :branch="flowDef"
            :index="i"
            :flowHistory="state.flowHistory"
            :flowInstId="props.flowInstId"
            @select="handleSelectNode"
            :is="NodeComponents[node.type]"
            @delete="deleteNode"
            @insertNode="insertNode"
          />
        </template>
      </div>
      <div v-else>
        <el-empty>加载中...</el-empty>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.w-process {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  width: 100%;
  height: auto;
  padding-bottom: 100px;
}
</style>
